Shellcode pour windows¶

2010

Pour notre premier shellcode, nous allons créer un shellcode en x86-32 pour afficher un message « Hello, World! ». Pour cela, il est utile d’avoir quelques connaissances de l’API Windows.

Concevoir un shellcode¶

Nous concevons ce code basique en C sous forme de shellcode. Ensuite, nous le réécrivons ci-dessous en assembleur ; pour cela, nous avons besoin de l’API Windows pour utiliser la fonction primitive.

#include <stdio.h>

int main() {
    printf("Hello, World\n");
    retrun 0;
}

Nous utilisons printf, qui est contenue dans la bibliothèque crtdll.dll. J’ai choisi une bibliothèque dynamique, non pas pour une question de performance, mais simplement pour me familiariser avec les bibliothèques dynamiques. La commande nmdll permet de connaître l’adresse associée à une fonction par rapport à une bibliothèque. L’adresse peut changer selon la version du système d’exploitation. Voici le résultat :

 > nmdll crtdll.dll | grep printf
 6C243255        _cprintf
 6C249847        _snprintf
 6C24989F        _snwprintf
 6C24B2D7        _vsnprintf
 6C24B32E        _vsnwprintf
 6C24C06C        fprintf
 6C24C792        fwprintf
 6C24D8F8        printf
 6C24E5C5        sprintf
 6C24F8FA        swprintf
 6C250097        vfprintf
 6C2500EE        vfwprintf
 6C250145        vprintf
 6C25018F        vsprintf
 6C2501E7        vswprintf
 6C25025D        vwprintf
 6C250D27        wprintf

Nous remplaçons retrun 0 par la fonction exit. Elle est également contenue dans la bibliothèque crtdll.dll. Utilisez nmdll pour connaître l’adresse associée à cette fonction :

> nmdll crtdll.dll | grep exit
6C242132        __dllonexit
6C25E004        _aexit_rtn_dll
6C241DB8        _amsg_exit
6C241F91        _c_exit
6C241F82        _cexit
6C241F71        _exit
6C24205F        _onexit
6C2420E7        atexit
6C241F60        exit

Construction du shellcode¶

Nous construisons le shellcode avec le compilateur nasm.

global	_main
    extern	_printf
    extern _exit

    section .data
    message	db	'Hello, World',12, 0

    section .text
_main:
    push	message
    call	_printf

    xor ebx, ebx
    push ebx
    call _exit

Suppression de toutes les sections

 global	_main
	extern	_printf
	extern _exit

 _main:

 jmp one
 two:

 call	_printf

 xor ebx, ebx
 push ebx
 call _exit

 one:
 call two
 db	'Hello, World',12, 0

Suppression du mot-clé extern. Nous avons vu ci-dessus qu’il avait une adresse. Nous allons donc les remplacer par leur adresse :

 global	_main

 _main:
	jmp short one
	two:
	mov eax, 0x6C24D8F8
	call eax

	xor ebx, ebx
	push ebx

	mov eax, 0x6C241F60
	call ebx

	one:
	call two
	db	'Hello, World',12

Compilation

nasm -f win32 helloworld.asm ld helloworld.obj

Après compilation, nous obtenons les opcodes

> objdump.exe -d .\helloworld.obj

.\helloworld2.obj:     file format pe-i386


Disassembly of section .text:

00000000 <_main>:
 0:   eb 11                   jmp    13 <one>

00000002 <two>:
 2:   b8 f8 d8 24 6c          mov    $0x6c24d8f8,%eax
 7:   ff d0                   call   *%eax
 9:   bb 60 1f 24 6c          mov    $0x6c241f60,%ebx
 e:   31 c0                   xor    %eax,%eax
10:   50                      push   %eax
11:   ff d3                   call   *%ebx

00000013 <one>:
13:   e8 ea ff ff ff          call   2 <two>
18:   48                      dec    %eax
19:   65                      gs
1a:   6c                      insb   (%dx),%es:(%edi)
1b:   6c                      insb   (%dx),%es:(%edi)
1c:   6f                      outsl  %ds:(%esi),(%dx)
1d:   2c 20                   sub    $0x20,%al
1f:   77 6f                   ja     90 <one+0x7d>
21:   72 6c                   jb     8f <one+0x7c>
23:   64                      fs
24:   0a                      .byte 0xa

Cela nous donne les opcodes suivants :

\\xeb\\x11\\xb8\\xf8\\xd8\\x24\\x6c\\xff\\xd0\\xbb\\x60\\x1f\\x24
\\x6c\\x31\\xc0\\x50\\xff\\xd3\\xe8\\xea\\xff\\xff\\xff\\x48\\x65
\\x6c\\x6c\\x6f\\x2c\\x20\\x77\\x6f\\x72\\x6c\\x64\\x0a

Testons le shellcode :

#include <windows.h>

char shellcode[] = "\\xEB\\x11\\xB8\\xF8\\xD8\\x24\\x6C\\xFF\\xD0\\xBB\\x60\\x1F\\x24\\x6C"
                   "\\x31\\xC0\\x50\\xFF\\xD3\\xE8\\xEA\\xFF\\xFF\\xFF\\x48\\x65\\x6C\\x6C"
                   "\\x6F\\x2C\\x20\\x77\\x6F\\x72\\x6C\\x64\\x0A";

int main (int argc, char **argv) {
    HMODULE lib = LoadLibrary("crtdll.dll");
    int (*ret)();              /* ret is a function pointer */
    ret = (int(*)())shellcode; /* ret points to our shellcode */
                                /* shellcode is type casted as a function */
    (int)(*ret)();             /* execute as function shellcode[] */
    FreeLibrary(lib);
    exit(0);                   /* exit() */
}

Attention avec ce shellcode, il est absolument nécessaire de charger la bibliothèque crtdll.dll, sinon le shellcode ne pourra pas fonctionner car les adresses des fonctions exit et printf ne pourront pas être trouvées.

Références :¶